package cn.mw.cmdb.trigger.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import cn.mw.cmdb.api.*;
import cn.mw.cmdb.entity.*;
import cn.mw.cmdb.enums.OperatorTypeDescEnum;
import cn.mw.cmdb.exception.AddTimeTaskException;
import cn.mw.cmdb.exception.JobClientNotExistException;
import cn.mw.cmdb.mongoMapper.InstanceInfoMapper;
import cn.mw.cmdb.mongoMapper.MwCmdbNotifyMapper;
import cn.mw.cmdb.mongoMapper.MwCmdbTriggerMapper;
import cn.mw.cmdb.param.InstanceSearchParam;
import cn.mw.cmdb.param.ModelSearchParam;
import cn.mw.cmdb.service.impl.*;
import cn.mw.cmdb.timeplan.param.MwTimePlanParam;
import cn.mw.cmdb.timeplan.service.MwTimePlanService;
import cn.mw.cmdb.trigger.*;
import cn.mw.cmdb.trigger.service.MwCmdbTriggerService;
import cn.mw.cmdb.util.CMDBTableTool;
import cn.mw.cmdb.util.CMDBTool;
import cn.mw.components.mongodb.entity.*;
import cn.mw.components.mongodb.page.MWPage;
import cn.mw.components.mongodb.tool.CriteriaWrapper;
import cn.mw.log.client.LogClientSimple;
import cn.mw.log.enums.BusinessLogType;
import cn.mw.log.enums.LogLevel;
import cn.mw.microMonitorCommon.api.cmdb.MwTimePlanCommonApi;
import cn.mw.microMonitorCommon.api.notify.NotifyDubboService;
import cn.mw.microMonitorCommon.constant.Constants;
import cn.mw.microMonitorCommon.entity.alertDto.PageData;
import cn.mw.microMonitorCommon.entity.notify.NotifyLogVO;
import cn.mw.microMonitorCommon.security.utils.SecurityUtils;
import cn.mw.microMonitorCommon.util.DateUtils;
import cn.mw.microMonitorCommon.util.I18NMessageUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboReference;
import org.apache.dubbo.config.annotation.DubboService;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.MessageSource;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import tech.powerjob.client.PowerJobClient;
import tech.powerjob.common.enums.*;
import tech.powerjob.common.model.LogConfig;
import tech.powerjob.common.request.http.SaveJobInfoRequest;
import tech.powerjob.common.request.query.JobInfoQuery;
import tech.powerjob.common.response.JobInfoDTO;
import tech.powerjob.common.response.ResultDTO;

import java.util.*;
import java.util.stream.Collectors;

@DubboService
@Service
@Slf4j
public class MwTriggerServiceImpl extends BaseSearchService<MwCmdbTrigger> implements MwCmdbTriggerDubboService
        , MwCmdbTriggerService, InitializingBean {

    @DubboReference(check = false, mock = "true" ,timeout = 15000)
    private NotifyDubboService notifyDubboService;

    @DubboReference(check = false, mock = "true" ,timeout = 15000)
    private MwTimePlanCommonApi mwTimePlanCommonApi;

    private I18NMessageUtils i18NMessageUtils;

    private LogClientSimple logClientSimple;

    private CmdbServiceManage cmdbServiceManage;

    private MwCmdbTriggerMapper mwCmdbTriggerMapper;

    private MwCmdbNotifyMapper mwCmdbNotifyMapper;

    private InstanceInfoMapper instanceInfoMapper;

    private PowerJobClient client;

    private MessageSource messageSource;

    @Value("${cmdb.timeTask.url}")
    private String timeTaskUrl;

    @Value("${cmdb.timeTask.user}")
    private String timeTaskUser;

    @Value("${cmdb.timeTask.passwd}")
    private String timeTaskPasswd;

    private MwTimePlanService mwTimePlanService;

    //字段下拉框不加入前缀的字段
    private Set<String> fieldDropdownExcludePrefix;

    //字段下拉框不显示字段的字段
    private Set<String> fieldDropdownExcludeField;


    public MwTriggerServiceImpl(MwCmdbTriggerMapper mwCmdbTriggerMapper
            , MwCmdbNotifyMapper mwCmdbNotifyMapper, InstanceInfoMapper instanceInfoMapper, MwTimePlanService mwTimePlanService
            , CmdbServiceManage cmdbServiceManage, MessageSource messageSource) {
        this.mwCmdbTriggerMapper = mwCmdbTriggerMapper;
        this.mwCmdbNotifyMapper = mwCmdbNotifyMapper;
        this.instanceInfoMapper = instanceInfoMapper;
        this.mwTimePlanService = mwTimePlanService;
        this.cmdbServiceManage = cmdbServiceManage;
        this.messageSource = messageSource;
    }

    @Override
    public List<MwTrigger> listAllTrigger(MwTriggerSearchParam mwTriggerSearchParam) {
        List<MwTrigger> ret = new ArrayList<>();
        SearchParam searchParam = new SearchParam();

        SubCondition subCondition = new SubCondition(CriteriaOpsType.is.name(), mwTriggerSearchParam.getTriggerType());
        searchParam.addSubCondition(CMDBTool.getFieldName(MwCmdbTrigger::getTriggerType), subCondition);

        subCondition = new SubCondition(CriteriaOpsType.is.name(), mwTriggerSearchParam.getBussinessType());
        searchParam.addSubCondition(CMDBTool.getFieldName(MwCmdbTrigger::getBussinessType), subCondition);

        subCondition = new SubCondition(CriteriaOpsType.lte.name(), mwTriggerSearchParam.getTriggerDate());
        searchParam.addSubCondition(CMDBTool.getFieldName(MwCmdbTrigger::getTrigDate), subCondition);
        Query query = genQuery(searchParam, null);

        List<MwCmdbTrigger> mwCmdbTriggers = mwCmdbTriggerMapper.find(query);

        if (null != mwCmdbTriggers) {
            for (MwCmdbTrigger mwCmdbTrigger : mwCmdbTriggers) {
                MwTrigger mwTrigger = new MwTrigger();
                BeanUtil.copyProperties(mwCmdbTrigger, mwTrigger);
                ret.add(mwTrigger);
            }
        }

        return ret;
    }

    @Override
    public InstanceSearchInfo listInstanceSearchInfo(MwNotifyInfo mwNotifyInfo) throws Exception {
        SearchParam searchParam = new SearchParam();
        InstanceSearchInfo instanceSearchInfo = new InstanceSearchInfo();

        searchParam.setSearchClass(MwCmdbNotify.class);
        SubCondition subCondition = new SubCondition(CriteriaOpsType.is.name(), InstanceSearchTrigger.class.getSimpleName());
        searchParam.addSubCondition(CMDBTool.getFieldName(MwCmdbNotify::getTriggerName), subCondition);

        Query query = new Query();
        Criteria criteria = genCriteria(searchParam);
        query.addCriteria(criteria);
        MwCmdbNotify mwCmdbNotify = mwCmdbNotifyMapper.findById(mwNotifyInfo.getId());

        if (null != mwCmdbNotify) {
            BeanUtil.copyProperties(mwCmdbNotify, mwNotifyInfo);
            instanceSearchInfo.setMwNotifyInfo(mwNotifyInfo);

            //根据配置查询实例信息
            //1.根据范围生成查询参数
            SearchParam mainSearchParam = new SearchParam();
            mainSearchParam.setIgnoreDataAuth(true);
            SearchParam subSearchParam = genScopeSearchParam(mwCmdbNotify.getScope());
            if (null != subSearchParam) {
                subSearchParam.setSearchClass(MwCmdbNotify.class);
                mainSearchParam.addSearchParam(subSearchParam);
            }

            //2.根据条件生成查询参数
            RuleGroupContext ruleGroupContext = genRuleSearchParam(mwCmdbNotify.getNotifyRule());
            if (null != ruleGroupContext.getSearchParam()) {
                subSearchParam.setSearchClass(MwCmdbNotify.class);
                mainSearchParam.addSearchParam(ruleGroupContext.getSearchParam());
            }

            //3.检查是否有分组统计
            GroupSearchOperation groupSearchOperation = null;
            if (null != ruleGroupContext.getGroupDetails()) {
                groupSearchOperation = new GroupSearchOperation();
                mainSearchParam.setGroupSearchOperation(groupSearchOperation);
                for (MwNotifyRuleConditionDetail detail : ruleGroupContext.getGroupDetails()) {
                    GroupCalculateMethodEnum cal = GroupCalculateMethodEnum.valueOf(detail.getFunction());
                    String projectField = TriggerUtil.genNotifyFieldByTarget(detail.getFunction(), detail.getObject());
                    groupSearchOperation.addCalculateField(projectField, cal, detail.getObject());
                }
            }

            query = new Query();
            mainSearchParam.setOperation(CriteriaOpsType.and.name());
            mainSearchParam.setSearchClass(InstanceInfo.class);
            criteria = genCriteria(mainSearchParam, true);
            if (null == criteria) {
                return instanceSearchInfo;
            }

            query.addCriteria(criteria);

            List<InstanceInfo> instanceInfos = null;
            List<Map> data = new ArrayList<>();
            if (null == mainSearchParam.getGroupSearchOperation()) {
                mainSearchParam.addProjectField(CMDBTool.getFieldName(InstanceInfo::getId));
                mainSearchParam.addProjectField(CMDBTool.getFieldName(InstanceInfo::getInstanceName));
                instanceInfos = CMDBTool.selectPageList(instanceInfoMapper, criteria, mainSearchParam);
                for (InstanceInfo instanceInfo : instanceInfos) {
                    Map map = new LinkedHashMap<>();
                    map.put(CMDBTool.getFieldName(InstanceInfo::getId), instanceInfo.getId());
                    map.put(CMDBTool.getFieldName(InstanceInfo::getInstanceName), instanceInfo.getInstanceName());
                    data.add(map);
                }
            } else {
                data = CMDBTool.aggregateAuthorizedList(InstanceInfo.class, Map.class, instanceInfoMapper, criteria, mainSearchParam);
            }

            if (!data.isEmpty()) {
                instanceSearchInfo.setData(data);
            }
        }
        return instanceSearchInfo;
    }

    @Override
    public List<MwNotifyInfo> listMwNotifyInfos(MwNotifyInfo mwNotifyInfo) throws Exception {
        SearchParam searchParam = new SearchParam();
        searchParam.setSearchClass(MwCmdbNotify.class);
        SubCondition subCondition = new SubCondition(CriteriaOpsType.is.name(), mwNotifyInfo.getExeType());
        searchParam.addSubCondition(CMDBTool.getFieldName(MwCmdbNotify::getExeType), subCondition);
        Criteria criteria = genCriteria(searchParam, true);
        List<MwCmdbNotify> mwCmdbNotifies = mwCmdbNotifyMapper.find(new Query(criteria));
        if (null != mwCmdbNotifies) {
            List<MwNotifyInfo> ret = new ArrayList<>();
            for (MwCmdbNotify cmdbNotify : mwCmdbNotifies) {
                MwNotifyInfo item = new MwNotifyInfo();
                BeanUtil.copyProperties(cmdbNotify, item);
                ret.add(item);
            }
            return ret;
        }
        return null;
    }

    @Override
    public void saveNotifyCount(List<MwTriggerCountDTO> mwTriggerCountDTOS) throws Exception {
        for (MwTriggerCountDTO mwTriggerCountDTO : mwTriggerCountDTOS) {
            MwCmdbNotify updMwCmdbNotify = new MwCmdbNotify();
            updMwCmdbNotify.setId(mwTriggerCountDTO.getId());
            updMwCmdbNotify.setNotifyCount(mwTriggerCountDTO.getNotifyCount());
            Query query = new Query(CriteriaWrapper.where(MwCmdbNotify::getId).is(mwTriggerCountDTO.getId()));
            Update update = CMDBTool.genMongoUpdate(updMwCmdbNotify, null, null);
            mwCmdbNotifyMapper.updateFirst(query, update);
        }
    }

    @Override
    public List<MwExpirationNoticeDto> getMwExpirationNoticeList() throws Exception {
        SearchParam param = new SearchParam();
        param.setSearchClass(MwCmdbNotify.class);
        Criteria criteria = genCriteria(param);
        List<MwCmdbNotify> mwCmdbNotifies = CMDBTool.selectAuthorizedList(MwCmdbNotify.class, mwCmdbNotifyMapper, criteria, param);
        if (null != mwCmdbNotifies) {
            List<MwExpirationNoticeDto> mwExpirationNoticeDtos = mwCmdbNotifies.stream().map(mwCmdbNotify -> {
                MwExpirationNoticeDto mwExpirationNoticeDto = new MwExpirationNoticeDto();
                mwExpirationNoticeDto.setExpirationNoticeName(mwCmdbNotify.getTitle());
                mwExpirationNoticeDto.setExpirationNoticeDays(mwCmdbNotify.getNotifyCount());
                return mwExpirationNoticeDto;
            }).collect(Collectors.toList());
            return mwExpirationNoticeDtos;
        }
        return null;
    }

    private SearchParam genScopeSearchParam(MwNofityScope scope) {
        SearchParam searchParam = new SearchParam();
        searchParam.setOperation(CriteriaOpsType.or.name());
        if (null != scope.getModelGroupIds()) {
            SubCondition subCondition = new SubCondition(CriteriaOpsType.in.name(), scope.getModelGroupIds());
            searchParam.addSubCondition(CMDBTool.getMongoSearchFieldName(InstanceInfo::getGroupId, InstanceInfo.class), subCondition);
        }

        if (null != scope.getModelIds()) {
            SubCondition subCondition = new SubCondition(CriteriaOpsType.in.name(), scope.getModelIds());
            searchParam.addSubCondition(CMDBTool.getMongoSearchFieldName(InstanceInfo::getModelId, InstanceInfo.class), subCondition);
        }

        if (null != scope.getInstanceIds()) {
            SubCondition subCondition = new SubCondition(CriteriaOpsType.in.name(), scope.getInstanceIds());
            searchParam.addSubCondition(CMDBTool.getMongoSearchFieldName(InstanceInfo::getId, InstanceInfo.class), subCondition);
        }

        if (null != searchParam.getCondition()) {
            return searchParam;
        }

        return null;
    }

    private RuleGroupContext genRuleSearchParam(MwNotifyRule notifyRule) {
        SearchParam searchParam = new SearchParam();
        RuleGroupContext groupContext = new RuleGroupContext();
        List<MwNotifyRuleConditionDetail> details = new ArrayList<>();
        switch (notifyRule.getRuleType()) {
            case or -> searchParam.setOperation(CriteriaOpsType.or.name());
            case and -> searchParam.setOperation(CriteriaOpsType.and.name());
        }

        if (null != notifyRule.getDetails()) {
            for (MwNotifyRuleConditionDetail detail : notifyRule.getDetails()) {
                if (!detail.isEnable()) {
                    continue;
                }
                switch (detail.getType()) {
                    case property:
                        PropertyType propertyType = PropertyTypeManage.getPropertyType(detail.getValueType().name().toLowerCase());
                        if (null != propertyType) {
                            Object value = propertyType.convertValue(detail.getValue());
                            SubCondition subCondition = new SubCondition(detail.getConditionOpsType().name(), value);
                            searchParam.addSubCondition(detail.getObject().toString(), subCondition);
                        } else {
                            log.error("find no propertype for {}", detail.getObject());
                        }

                        break;
                    case target:
                        details.add(detail);
                        break;
                }

            }
        }

        if (null != searchParam.getCondition()) {
            groupContext.setSearchParam(searchParam);
        }

        if (!details.isEmpty()) {
            groupContext.setGroupDetails(details);
        }
        return groupContext;
    }


    @Override
    protected MwCmdbTrigger genObject() {
        return MwCmdbTrigger.builder().build();
    }

    @Override
    public MwCmdbNotifyParam saveNotify(MwCmdbNotifyParam param) throws Exception {

        if (null == client) {
            throw new JobClientNotExistException();
        }

        MwCmdbNotify mwCmdbNotify = new MwCmdbNotify();
        MwCmdbNotify oldMwCmdbNotify = new MwCmdbNotify();
        BeanUtil.copyProperties(param, mwCmdbNotify);
        mwCmdbNotify.extractFrom(param);
        if (StringUtils.hasText(param.getId())) {
            oldMwCmdbNotify = mwCmdbNotifyMapper.findById(param.getId());
        }


        //如果是更新,需要查询,比对时间计划是否改变
        if (StringUtils.hasText(param.getId())) {
            if (!oldMwCmdbNotify.compareTimePlanId(mwCmdbNotify) && StringUtils.hasText(mwCmdbNotify.getTimePlanId())) {
                addTimeTask(mwCmdbNotify, param, oldMwCmdbNotify);
            }
        } else {
            mwCmdbNotify.setId(param.getId());
            param.setId(param.getId());
            addTimeTask(mwCmdbNotify, param, null);
        }

        Query query = new Query(CriteriaWrapper.where(MwCmdbNotify::getId).is(mwCmdbNotify.getId()));
        MwCmdbNotify notify = mwCmdbNotifyMapper.findById(param.getId());
        if (ObjectUtil.isNotEmpty(notify)) {
            logClientSimple.addBusinessLog(LogLevel.INFO.getId(), BusinessLogType.FLOWABLE_MANAGE.getId(),
                    i18NMessageUtils.getMessage("mwCmdb-operation-log", new Object[]{SecurityUtils.getUser().getNickName(), DateUtils.now()
                            , BusinessLogType.SYSTEM_MANAGE.getCnName(), OperatorTypeDescEnum.update.getCname(),
                            i18NMessageUtils.getMessage("notify-update", new Object[]{param.getTitle()}, LocaleContextHolder.getLocale()),
                            Constants.OperationStatus.SUCCESS}, LocaleContextHolder.getLocale()));
        } else {
            logClientSimple.addBusinessLog(LogLevel.INFO.getId(), BusinessLogType.FLOWABLE_MANAGE.getId(),
                    i18NMessageUtils.getMessage("mwCmdb-operation-log", new Object[]{SecurityUtils.getUser().getNickName(), DateUtils.now()
                            , BusinessLogType.SYSTEM_MANAGE.getCnName(), OperatorTypeDescEnum.update.getCname(),
                            i18NMessageUtils.getMessage("notify-add", new Object[]{param.getTitle()}, LocaleContextHolder.getLocale()),
                            Constants.OperationStatus.SUCCESS}, LocaleContextHolder.getLocale()));
        }
        MwCmdbNotify ret = mwCmdbNotifyMapper.save(mwCmdbNotify);

//        if (null != mwCmdbNotify.getTaskIds()) {
//            MwCmdbNotify updMwCmdbNotify = new MwCmdbNotify();
//            updMwCmdbNotify.setId(mwCmdbNotify.getId());
//            updMwCmdbNotify.setTaskIds(mwCmdbNotify.getTaskIds());
//            if (mwCmdbNotify.getNotifyCount() != null) {
//                updMwCmdbNotify.setNotifyCount(mwCmdbNotify.getNotifyCount());
//            }
//            Query query = new Query(CriteriaWrapper.where(MwCmdbNotify::getId).is(mwCmdbNotify.getId()));
//            Update update = CMDBTool.genMongoUpdate(updMwCmdbNotify, null, null);
//            mwCmdbNotifyMapper.updateFirst(query, update);
//        }

        return param;
    }

    @Override
    public MwCmdbNotifyDelParam deleteNotify(MwCmdbNotifyDelParam param) throws Exception {
        List<String> ids = param.getIds();
        if (null != ids) {
            SearchParam searchParam = new SearchParam();
            searchParam.setSearchClass(MwCmdbNotify.class);
            SubCondition subCondition = new SubCondition(CriteriaOpsType.in.name(), ids);
            searchParam.addSubCondition(CMDBTool.getFieldName(MwCmdbNotify::getId), subCondition);
            Criteria criteria = genCriteria(searchParam);
            List<MwCmdbNotify> mwCmdbNotifys = mwCmdbNotifyMapper.find(new Query(criteria));
            if (null != mwCmdbNotifys) {
                for (MwCmdbNotify mwCmdbNotify : mwCmdbNotifys) {
                    if (null != mwCmdbNotify.getTaskIds()) {
                        for (Long taskId : mwCmdbNotify.getTaskIds()) {
                            client.deleteJob(taskId);
                        }
                    }
                }
            }

            mwCmdbNotifyMapper.remove(new Query(CriteriaWrapper.where(MwCmdbNotify::getId).in(ids)));
            return param;
        }
        return null;
    }

    @Override
    public MwCmdbNotifyParam selectNotify(MwCmdbNotifyParam param) throws Exception {
        MwCmdbNotify mwCmdbNotify = mwCmdbNotifyMapper.findById(param.getId());
        BeanUtil.copyProperties(mwCmdbNotify, param);

        //查询范围对应实例,模型, 分组信息
        if (null != mwCmdbNotify.getScope()) {
            Map<String, String> idMap = findCmdbIdMap(mwCmdbNotify.getScope());
            param.extractFrom(mwCmdbNotify, idMap);
        }
        return param;
    }

    @Override
    public MWPage listNotify(SearchParam param) throws Exception {
        param.setSearchClass(MwCmdbNotify.class);
        Criteria criteria = genCriteria(param);
        List<MwCmdbNotify> mwCmdbNotifies = CMDBTool.selectAuthorizedList(MwCmdbNotify.class, mwCmdbNotifyMapper, criteria, param);
        if (null != mwCmdbNotifies) {
            List<MwCmdbNotifyParam> ret = new ArrayList<>();
            for (MwCmdbNotify mwCmdbNotify : mwCmdbNotifies) {
                MwCmdbNotifyParam item = new MwCmdbNotifyParam();
                BeanUtil.copyProperties(mwCmdbNotify, item);
                if (null != item.getExeType()) {
                    String key = TriggerConstants.ExeTypePrefix + item.getExeType().name();
                    String name = messageSource.getMessage(key, null, LocaleContextHolder.getLocale());
                    item.setExeTypeName(name);
                }
                ret.add(item);
            }
            param.getPage().setRecords(ret);
            return param.getPage();

        }
        return null;
    }

    @Override
    public MwCmdbNotifyDropdown listDropdown() throws Exception {
        MwCmdbNotifyDropdown mwCmdbNotifyDropdown = new MwCmdbNotifyDropdown();
        mwCmdbNotifyDropdown.init(messageSource);
        return mwCmdbNotifyDropdown;
    }

    @Override
    public Map listFieldDropdown(MwNofityScope scope) throws Exception {
        CustomModelServiceImpl service = (CustomModelServiceImpl) cmdbServiceManage.getModelService(CustomModelServiceImpl.ID);
        List<String> modelIds = new ArrayList<>();
        Map ret = null;
        //1.添加要查询的模型id
        if (null != scope.getModelIds()) {
            modelIds.addAll(scope.getModelIds());
        }

        //2.如果范围有模型分组,模型,实例,则返回父模型的所有属性
        List<String> idFields = new ArrayList<>();
        idFields.add(CMDBTool.getFieldName(ModelInfo::getId));
        if (null != scope.getModelGroupIds()) {
            ModelSearchParam modelSearchParam = new ModelSearchParam();
            SubCondition subCondition = new SubCondition(CriteriaOpsType.elemMatch.name(), scope.getModelGroupIds());
            modelSearchParam.addSubCondition(CMDBTool.getFieldName(ModelInfo::getGroupPath), subCondition);

            modelSearchParam.setFields(idFields);
            List<ModelInfo> modelInfos = service.selectList(modelSearchParam);
            if (null != modelInfos) {
                for (ModelInfo modelInfo : modelInfos) {
                    modelIds.add(modelInfo.getId());
                }
            }
        }

        if (null != scope.getInstanceIds()) {
            InstanceServiceImpl instanceService = (InstanceServiceImpl) cmdbServiceManage.getModelService(InstanceServiceImpl.ID);
            InstanceSearchParam instanceSearchParam = new InstanceSearchParam();
            instanceSearchParam.setInstanceIds(scope.getInstanceIds());
            instanceSearchParam.convert();
            List<String> fields = new ArrayList<>();
            fields.add(CMDBTool.getFieldName(InstanceInfo::getModelId));
            instanceSearchParam.setFields(fields);
            List<InstanceInfo> instanceInfos = instanceService.selectList(instanceSearchParam);
            if (null != instanceInfos && !instanceInfos.isEmpty()) {
                Set modelSet = instanceInfos.stream().map(InstanceInfo::getModelId).collect(Collectors.toSet());
                for (Object value : modelSet) {
                    if (!modelIds.contains(value.toString())) {
                        modelIds.add(value.toString());
                    }
                }

            }
        }

        //通过父模型id,获取属性信息
        if (modelIds.size() > 1) {
            ModelSearchParam modelSearchParam = new ModelSearchParam();
            modelSearchParam.setModelIds(modelIds);
            modelSearchParam.convert();
            List<String> fields = new ArrayList<>();
            fields.add(CMDBTool.getFieldName(ModelInfo::getParentModelIds));
            modelSearchParam.setFields(fields);
            List<ModelInfo> modelInfos = service.selectList(modelSearchParam);
            if (null != modelInfos) {
                List<String> parentIds = new ArrayList<>();
                for (ModelInfo modelInfo : modelInfos) {
                    if (null != modelInfo.getParentModelIds()) {
                        for (String parentId : modelInfo.getParentModelIds()) {
                            if (!parentIds.contains(modelInfo.getParentModelIds())) {
                                parentIds.add(parentId);
                            }

                        }
                    }
                }

                if (!parentIds.isEmpty()) {
                    modelSearchParam = new ModelSearchParam();
                    modelSearchParam.setModelIds(parentIds);
                    modelInfos = service.selectList(modelSearchParam);
                    ret = getModelPropertyMap(modelInfos, new ModelInfoFilterPropertyId() {
                        @Override
                        public boolean fiterPrefix(String id) {
                            return fieldDropdownExcludePrefix.contains(id);
                        }

                        @Override
                        public boolean filterData(String id) {
                            return fieldDropdownExcludeField.contains(id);
                        }
                    });
                }
            }
        } else if (modelIds.size() == 1) {
            List<ModelInfo> modelInfos = service.findByIds(modelIds);
            if (null != modelInfos) {
                ret = getModelPropertyMap(modelInfos, new ModelInfoFilterPropertyId() {
                    @Override
                    public boolean fiterPrefix(String id) {
                        return fieldDropdownExcludePrefix.contains(id);
                    }

                    @Override
                    public boolean filterData(String id) {
                        return fieldDropdownExcludeField.contains(id);
                    }
                });
            }
        }

        return ret;
    }

    private Map getModelPropertyMap(List<ModelInfo> modelInfos, ModelInfoFilterPropertyId filterPrefix) {
        Map ret = new LinkedHashMap();
        for (ModelInfo modelInfo : modelInfos) {
            ret.putAll(modelInfo.getCurrentModelPropertyKeyMapWithInstancePrefix(filterPrefix));
        }
        return ret;
    }


    private void addTimeTask(MwCmdbNotify mwCmdbNotify, MwCmdbNotifyParam param, MwCmdbNotify oldMwCmdbNotify) {
        if (null != mwCmdbNotify.getScope()
                && null != mwCmdbNotify.getNotifyRule()
                && null != mwCmdbNotify.getExeType() && MwNotifyExeType.active == mwCmdbNotify.getExeType()
                && null != mwCmdbNotify.getMessageRules()
                && StrUtil.isNotBlank(param.getTimePlanId())
        ) {
            //查询时间计划
            MwTimePlanParam mwTimePlanParam = new MwTimePlanParam();
            mwTimePlanParam.setId(param.getTimePlanId());
            MwTimePlanParam timePlan = mwTimePlanService.select(mwTimePlanParam);

            if (null != timePlan.getCrons()) {
                //先删除旧的定时任务
                if (null != oldMwCmdbNotify && null != oldMwCmdbNotify.getTaskIds()) {
                    for (Long taskId : oldMwCmdbNotify.getTaskIds()) {
                        client.deleteJob(taskId);
                    }
                }

                List<Long> taskIds = new ArrayList<>();
                int index = -1;
                if (timePlan.getCrons().size() == 1) {
                    index = -2;
                }
                for (String cron : timePlan.getCrons()) {
                    index++;
                    SaveJobInfoRequest saveJobInfoRequest = new SaveJobInfoRequest();
                    if (index >= 0) {
                        saveJobInfoRequest.setJobName(mwCmdbNotify.getTitle() + index);
                    } else {
                        saveJobInfoRequest.setJobName(mwCmdbNotify.getTitle());
                    }

                    JobParam jobParam = new JobParam();
                    jobParam.setMwNotifyId(mwCmdbNotify.getId());
                    saveJobInfoRequest.setJobParams(JSONUtil.toJsonStr(jobParam));
                    saveJobInfoRequest.setTimeExpressionType(TimeExpressionType.CRON);
                    saveJobInfoRequest.setTimeExpression(cron);
                    saveJobInfoRequest.setExecuteType(ExecuteType.STANDALONE);
                    saveJobInfoRequest.setProcessorType(ProcessorType.BUILT_IN);
                    saveJobInfoRequest.setDispatchStrategy(DispatchStrategy.HEALTH_FIRST);
                    saveJobInfoRequest.setMaxInstanceNum(1);
                    saveJobInfoRequest.setMaxWorkerCount(1);
                    saveJobInfoRequest.setConcurrency(1);

                    LogConfig logConfig = new LogConfig();
                    logConfig.setType(LogType.LOCAL_AND_ONLINE.getV());
                    saveJobInfoRequest.setLogConfig(logConfig);
                    //跟job-worker里的bean名称对应
                    saveJobInfoRequest.setProcessorInfo("mwNotifyActiveProcessor");
                    ResultDTO<Long> resultDTO = client.saveJob(saveJobInfoRequest);
                    if (!resultDTO.isSuccess()) {
                        throw new AddTimeTaskException();
                    }
                    taskIds.add(resultDTO.getData());
                }
                if (taskIds.size() > 0) {
                    //保存更新taskId
                    mwCmdbNotify.setTaskIds(taskIds);
                }
            }

        }
    }

    @Override
    public void afterPropertiesSet() {
        fieldDropdownExcludePrefix = new HashSet<>();
        fieldDropdownExcludePrefix.add(CMDBTool.getFieldName(DataAuth::getOrgs));
        fieldDropdownExcludePrefix.add(CMDBTool.getFieldName(DataAuth::getGroups));
        fieldDropdownExcludePrefix.add(CMDBTool.getFieldName(DataAuth::getUsers));

        fieldDropdownExcludeField = new HashSet<>();
        fieldDropdownExcludeField.add(DataAuth.getNamesFieldName(CMDBTool.getFieldName(DataAuth::getOrgs)));
        fieldDropdownExcludeField.add(DataAuth.getNamesFieldName(CMDBTool.getFieldName(DataAuth::getGroups)));
        fieldDropdownExcludeField.add(DataAuth.getNamesFieldName(CMDBTool.getFieldName(DataAuth::getUsers)));
        try {
            client = new PowerJobClient(timeTaskUrl, timeTaskUser, timeTaskPasswd);

            JobInfoQuery jobInfoQuery = new JobInfoQuery();
            jobInfoQuery.setJobNameEq(TriggerConstants.PassiveNotifyName).setProcessorInfoEq(TriggerConstants.NotifyPassiveProcessor).setStatusIn(List.of(1));
            ResultDTO<List<JobInfoDTO>> resultJobDTO = client.queryJob(jobInfoQuery);
            if (CollUtil.isEmpty(resultJobDTO.getData())) {
                SaveJobInfoRequest saveJobInfoRequest = new SaveJobInfoRequest();
                saveJobInfoRequest.setJobName(TriggerConstants.PassiveNotifyName);
                saveJobInfoRequest.setTimeExpressionType(TimeExpressionType.CRON);
                saveJobInfoRequest.setTimeExpression(TriggerConstants.PassiveCron);
                saveJobInfoRequest.setExecuteType(ExecuteType.STANDALONE);
                saveJobInfoRequest.setProcessorType(ProcessorType.BUILT_IN);
                saveJobInfoRequest.setDispatchStrategy(DispatchStrategy.HEALTH_FIRST);
                saveJobInfoRequest.setMaxInstanceNum(1);
                saveJobInfoRequest.setMaxWorkerCount(1);
                saveJobInfoRequest.setConcurrency(1);

                LogConfig logConfig = new LogConfig();
                logConfig.setType(LogType.LOCAL_AND_ONLINE.getV());
                saveJobInfoRequest.setLogConfig(logConfig);
                //跟job-worker里的bean名称对应
                saveJobInfoRequest.setProcessorInfo(TriggerConstants.NotifyPassiveProcessor);
                client.saveJob(saveJobInfoRequest);
            }
        } catch (Exception e) {
            log.error("trigger manage:{}", e);
        }
    }

    private class RuleGroupContext {
        private SearchParam searchParam;
        private List<MwNotifyRuleConditionDetail> groupDetails;

        public RuleGroupContext() {
            this.searchParam = searchParam;
            this.groupDetails = groupDetails;
        }

        public SearchParam getSearchParam() {
            return searchParam;
        }

        public List<MwNotifyRuleConditionDetail> getGroupDetails() {
            return groupDetails;
        }

        public void setSearchParam(SearchParam searchParam) {
            this.searchParam = searchParam;
        }

        public void setGroupDetails(List<MwNotifyRuleConditionDetail> groupDetails) {
            this.groupDetails = groupDetails;
        }
    }

    @Override
    public ModelInfoFilterPropertyId getModelInfoFilterPropertyId() {
        return new ModelInfoFilterPropertyId() {
            @Override
            public boolean fiterPrefix(String id) {
                return fieldDropdownExcludePrefix.contains(id);
            }

            @Override
            public boolean filterData(String id) {
                return fieldDropdownExcludeField.contains(id);
            }
        };
    }

    @Override
    public List<MwNotifyByScopeView> listNotifyByScope(MwNotifyScopeSearchParam searchParam) throws Exception {
        //1.判断是否输入关键字查询信息,如果数据关键字查询,先查询出对应的分组,模型,实例信息
        String keyword = searchParam.getKeywordValue();
        SearchParam notifySearchParam = new SearchParam();
        notifySearchParam.setPage(searchParam.getPage());
        List<String> modelGroupIds = searchParam.getModelGroupIds();
        List<String> modelIds = searchParam.getModelIds();
        List<String> intanceIds = searchParam.getIntanceIds();
        if (StringUtils.hasText(searchParam.getOperation())
                && CriteriaOpsType.keyword == CriteriaOpsType.valueOf(searchParam.getOperation())
                && StringUtils.hasText(keyword)) {

            List<ModelGroupInfo> modelGroupInfos = null;
            List<ModelInfo> modelInfos = null;
            List<InstanceInfo> instanceInfos = null;

            //查询分组信息
            List<String> fields = new ArrayList<>();
            fields.add(CMDBTool.getFieldName(ModelGroupInfo::getId));
            fields.add(CMDBTool.getFieldName(ModelGroupInfo::getName));
            ModelGroupServiceImpl modelGroupService = (ModelGroupServiceImpl) cmdbServiceManage.getModelService(ModelGroupServiceImpl.ID);
            SearchParam groupSearchparam = new SearchParam();
            BeanUtil.copyProperties(searchParam, groupSearchparam);
            groupSearchparam.setFields(fields);
            modelGroupInfos = modelGroupService.doSelectList(groupSearchparam);

            if (null != modelGroupInfos && !modelGroupInfos.isEmpty()) {
                modelGroupIds = modelGroupInfos.stream().map(ModelGroupInfo::getId).collect(Collectors.toList());
            }

            //查询模型信息
            CustomModelServiceImpl modelService = (CustomModelServiceImpl) cmdbServiceManage.getModelService(CustomModelServiceImpl.ID);
            ModelSearchParam modelSearchparam = new ModelSearchParam();
            fields = new ArrayList<>();
            fields.add(CMDBTool.getFieldName(ModelInfo::getId));
            fields.add(CMDBTool.getFieldName(ModelInfo::getModelName));

            BeanUtil.copyProperties(searchParam, modelSearchparam);
            modelSearchparam.setFields(fields);

            modelInfos = modelService.doSelectNormalModelList(modelSearchparam);
            if (null != modelInfos && !modelInfos.isEmpty()) {
                modelIds = modelInfos.stream().map(ModelInfo::getId).collect(Collectors.toList());
            }


            //查询实例信息
            InstanceServiceImpl instanceService = (InstanceServiceImpl) cmdbServiceManage.getModelService(InstanceServiceImpl.ID);
            InstanceSearchParam instanceSearchparam = new InstanceSearchParam();
            fields = new ArrayList<>();
            fields.add(CMDBTool.getFieldName(InstanceInfo::getId));
            fields.add(CMDBTool.getFieldName(InstanceInfo::getInstanceName));

            BeanUtil.copyProperties(searchParam, instanceSearchparam);
            instanceSearchparam.setFields(fields);
            instanceInfos = instanceService.selectList(instanceSearchparam);
            if (null != instanceInfos && !instanceInfos.isEmpty()) {
                intanceIds = instanceInfos.stream().map(InstanceInfo::getId).collect(Collectors.toList());
            }
        } else if (StringUtils.hasText(searchParam.getApplicationRelatedId())) {
            //查询提醒对应的范围
            String applicationRelatedId = searchParam.getApplicationRelatedId();
            String[] split = applicationRelatedId.split("\\.");
            List<String> applicationRelatedIdList = Collections.singletonList(split[1]);
            MwNotifyScopeType scopeType = MwNotifyScopeType.getByName(split[0]);
            switch (scopeType) {
                case modelGroup:
                    modelGroupIds = applicationRelatedIdList;
                    break;
                case model:
                    modelIds = applicationRelatedIdList;
                    break;
                case instance:
                    intanceIds = applicationRelatedIdList;
                    break;
            }
        }

        if (null != modelGroupIds) {
            String[] notifyFields = {CMDBTool.getFieldName(MwCmdbNotify::getScope), CMDBTool.getFieldName(MwNofityScope::getModelGroupIds)};
            doAddNotifySearchParam(notifyFields, notifySearchParam, modelGroupIds);
        }

        if (null != modelIds) {
            String[] notifyFields = {CMDBTool.getFieldName(MwCmdbNotify::getScope), CMDBTool.getFieldName(MwNofityScope::getModelIds)};
            doAddNotifySearchParam(notifyFields, notifySearchParam, modelIds);
        }

        if (null != intanceIds) {
            String[] notifyFields = {CMDBTool.getFieldName(MwCmdbNotify::getScope), CMDBTool.getFieldName(MwNofityScope::getInstanceIds)};
            doAddNotifySearchParam(notifyFields, notifySearchParam, intanceIds);

        }

        //2.根据分组,模型,实例id查询关联提醒信息
        List<MwCmdbNotify> mwCmdbNotifies = null;
        if (null != notifySearchParam.getCondition() && !notifySearchParam.getCondition().isEmpty()) {
            notifySearchParam.setSearchClass(MwCmdbNotify.class);
            Criteria criteria = genCriteria(notifySearchParam, true);
            mwCmdbNotifies = CMDBTool.selectAuthorizedList(MwCmdbNotify.class, mwCmdbNotifyMapper, criteria, notifySearchParam);
        }

        //3.根据查询到的提醒信息,构造返回数据
        if (null != mwCmdbNotifies && !mwCmdbNotifies.isEmpty()) {
            List<MwNotifyByScopeView> mwNotifyByScopeViews = null;
            Map<String, List<MwCmdbNotify>> map = new HashMap<>();
            for (MwCmdbNotify mwCmdbNotify : mwCmdbNotifies) {
                MwNofityScope scope = mwCmdbNotify.getScope();
                if (null != scope) {
                    doGroupMapByIds(MwNotifyScopeType.modelGroup, scope.getModelGroupIds(), mwCmdbNotify, map);
                    doGroupMapByIds(MwNotifyScopeType.model, scope.getModelIds(), mwCmdbNotify, map);
                    doGroupMapByIds(MwNotifyScopeType.instance, scope.getInstanceIds(), mwCmdbNotify, map);
                }
            }

            if (!map.isEmpty()) {
                mwNotifyByScopeViews = new ArrayList<>();
                for (Map.Entry<String, List<MwCmdbNotify>> entry : map.entrySet()) {
                    MwNotifyByScopeView mwNotifyByScopeView = new MwNotifyByScopeView();
                    String[] ids = entry.getKey().split("-");
                    String id = ids[0];
                    mwNotifyByScopeView.setId(id);

                    MwNotifyScopeType type = MwNotifyScopeType.valueOf(ids[1]);
                    boolean filter = true;
                    if (null != modelGroupIds && MwNotifyScopeType.modelGroup == type) {
                        if (modelGroupIds.contains(id)) {
                            filter = false;
                        }
                    }

                    if (null != modelIds && MwNotifyScopeType.model == type) {
                        if (modelIds.contains(id)) {
                            filter = false;
                        }
                    }

                    if (null != intanceIds && MwNotifyScopeType.instance == type) {
                        if (intanceIds.contains(id)) {
                            filter = false;
                        }
                    }

                    if (filter) {
                        continue;
                    }

                    String key = TriggerConstants.ScopeTypePrefix + type.name();
                    mwNotifyByScopeView.setType(messageSource.getMessage(key, null, LocaleContextHolder.getLocale()));
                    for (MwCmdbNotify mwCmdbNotify : entry.getValue()) {
                        MwNotifyOverView mwNotifyOverView = new MwNotifyOverView(mwCmdbNotify.getId(), mwCmdbNotify.getTitle());
                        mwNotifyByScopeView.addMwNotifyOverView(mwNotifyOverView);
                    }
                    mwNotifyByScopeViews.add(mwNotifyByScopeView);
                }
            }

            if (null != mwNotifyByScopeViews) {
                return mwNotifyByScopeViews;
            }
        }
        return null;
    }

    @Override
    public PageData listNotifyLog(SearchParam param) {
        PageData page = new PageData<>();
        page.setCurrent(param.getPage().getCurrent());
        page.setSize(param.getPage().getSize());
        PageData<NotifyLogVO> logVOPageData = notifyDubboService.listNotifyLogVO(page);
        return logVOPageData;
    }

    @Override
    public Integer deleteNotifyLog(MwCmdbNotifyLogDelParam param) {
        return notifyDubboService.deleteNotifyLog(param.getIds());
    }


    private void doAddNotifySearchParam(String[] notifyFields, SearchParam notifySearchParam, List<String> ids) {
        String notifyKey = CMDBTableTool.getMongoFieldPath(notifyFields);
        SubCondition modelGroupCondition = new SubCondition(CriteriaOpsType.in.name(), ids);
        notifySearchParam.addSubCondition(notifyKey, modelGroupCondition);
    }

    private void doGroupMapByIds(MwNotifyScopeType scopeType, List<String> ids, MwCmdbNotify mwCmdbNotify, Map<String, List<MwCmdbNotify>> map) {
        if (null != ids) {
            for (String id : ids) {
                String key = id + "-" + scopeType.name();
                List<MwCmdbNotify> list = map.get(key);
                if (null == list) {
                    list = new ArrayList<>();
                    map.put(key, list);
                }
                list.add(mwCmdbNotify);
            }
        }
    }

    private Map<String, String> findCmdbIdMap(MwNofityScope scope) throws Exception {
        Map<String, String> ret = new HashMap<>();
        if (null != scope.getModelGroupIds() && !scope.getModelGroupIds().isEmpty()) {
            ModelGroupServiceImpl service = (ModelGroupServiceImpl) cmdbServiceManage.getModelService(ModelGroupServiceImpl.ID);
            List<ModelGroupInfo> modelGroupInfos = service.doSelectByIds(scope.getModelGroupIds());
            if (null != modelGroupInfos) {
                for (ModelGroupInfo modelGroupInfo : modelGroupInfos) {
                    ret.put(modelGroupInfo.getId(), modelGroupInfo.getName());
                }
            }
        }

        if (null != scope.getModelIds() && !scope.getModelIds().isEmpty()) {
            CustomModelServiceImpl service = (CustomModelServiceImpl) cmdbServiceManage.getModelService(CustomModelServiceImpl.ID);
            List<ModelInfo> modelInfos = service.findByIds(scope.getModelIds());
            if (null != modelInfos) {
                for (ModelInfo modelInfo : modelInfos) {
                    ret.put(modelInfo.getId(), modelInfo.getModelName());
                }
            }
        }

        if (null != scope.getInstanceIds() && !scope.getInstanceIds().isEmpty()) {
            InstanceServiceImpl instanceService = (InstanceServiceImpl) cmdbServiceManage.getModelService(InstanceServiceImpl.ID);
            InstanceSearchParam searchParam = new InstanceSearchParam();
            searchParam.setInstanceIds(scope.getInstanceIds());
            List<String> fields = new ArrayList<>();
            fields.add(CMDBTool.getFieldName(InstanceInfo::getId));
            fields.add(CMDBTool.getFieldName(InstanceInfo::getInstanceName));
            searchParam.setFields(fields);

            List<InstanceInfo> instanceInfos = instanceService.selectListByIds(searchParam);
            if (null != instanceInfos) {
                for (InstanceInfo instanceInfo : instanceInfos) {
                    ret.put(instanceInfo.getId(), instanceInfo.getInstanceName());
                }
            }
        }

        if (!ret.isEmpty()) {
            return ret;
        }

        return null;
    }
}
